package com.wutianyi.shiro;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheFactory;
import net.sf.jsr107cache.CacheManager;

import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.appengine.api.memcache.jsr107cache.GCacheFactory;

public class CacheSessionDaoImpl extends AbstractSessionDAO {
	
	private static final Logger log = LoggerFactory.getLogger(CacheSessionDaoImpl.class);
	private Cache cache;
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public CacheSessionDaoImpl() {
		Map props = new HashMap();
		props.put(GCacheFactory.EXPIRATION_DELTA, 3600);
		
		try {
			CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
			cache = cacheFactory.createCache(props);
		} catch (CacheException e) {
			log.error("", e);
		}
	}
	
	@Override
	public void delete(Session session) {
		if (null == session) {
			throw new NullPointerException("session argument cannot be null.");
		}
		Serializable id = session.getId();
		if (id != null) {
			cache.remove(id);
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public Collection<Session> getActiveSessions() {
		Collection<Session> values = cache.values();
		if (CollectionUtils.isEmpty(values)) {
			return Collections.emptySet();
		} else {
			return Collections.unmodifiableCollection(values);
		}
	}
	
	@Override
	public void update(Session session) throws UnknownSessionException {
		storeSession(session.getId(), session);
	}
	
	@Override
	protected Serializable doCreate(Session session) {
		Serializable sessionId = generateSessionId(session);
		assignSessionId(session, sessionId);
		storeSession(sessionId, session);
		return sessionId;
	}
	
	@Override
	protected Session doReadSession(Serializable sessionId) {
		if (null == sessionId) {
			return null;
		}
		return (Session) cache.get(sessionId);
	}
	
	private Session storeSession(Serializable id, Session session) {
		if (id == null) {
			throw new NullPointerException("id argument cannot be null.");
		}
		return (Session) cache.put(id, session);
	}
}
